package jp.reflexworks.invoice;

import java.io.IOException;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.logging.Logger;

import javax.jdo.JDOException;
import javax.jdo.JDOObjectNotFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jp.reflexworks.gae.servlet.ReflexServlet;
import jp.reflexworks.gae.util.HttpStatus;
import jp.reflexworks.gae.util.RequestMapper;
import jp.reflexworks.gae.util.Status;
import jp.reflexworks.invoice.model.Invoice;
import jp.reflexworks.invoice.model.InvoiceBase;
import jp.reflexworks.invoice.model.Order;
import jp.reflexworks.invoice.util.JdoUtils;

@SuppressWarnings("serial")
public class InvoiceServlet extends ReflexServlet {
	
	Logger logger = Logger.getLogger(this.getClass().getName());
	private static final String MODEL_PACKAGE = "jp.reflexworks.invoice.model";

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		
		boolean toXml = true;
		if (req.getParameter("xml")!=null) {
			toXml = false;	// toJSON
		}

		try {
			Invoice param = new Invoice();
			(new RequestMapper()).setValue(req, param);
			
			JdoUtils jdoUtils = new JdoUtils();
			
			String insertCntStr = req.getParameter("init");

			if (insertCntStr!=null) {
				
				String[] idx = null;
				if (insertCntStr.indexOf("-") > 0) {
					idx = insertCntStr.split("-");
				} else {
					idx = new String[2];
					idx[0] = "1";
					idx[1] = insertCntStr;
				}

				List<Invoice> recList = new ArrayList<Invoice>();
				for (long i = Long.parseLong(idx[0]); i <= Long.parseLong(idx[1]); i++) {
					Invoice rec = Instance.newInvoice(i);
					recList.add(rec);
				}
				jdoUtils.insert(recList);
				
				Status status = new Status();
				status.code = HttpStatus.SC_CREATED;
				status.message = "Created.";
				doResponse(resp, status, toXml, MODEL_PACKAGE);
			}else {

			String id = req.getParameter("id");
			// idで検索getEntriesById
			// invoiceNoで検索	
			if (id!=null) {
				Invoice invoice = jdoUtils.getInvoiceById(param);

				if (invoice == null ) {
					Status status = new Status();
					status.code = HttpStatus.SC_NO_CONTENT;
					status.message = "No data.";
					try {
						doResponse(resp, status, toXml, MODEL_PACKAGE);
					} catch (Exception ee) {
						ee.printStackTrace();
					}
				} else {
					doResponse(resp, invoice , toXml, MODEL_PACKAGE);	// true:JSON
				}
				doResponse(resp, invoice, toXml,MODEL_PACKAGE);	// true:JSON
			}else 
			if (param.invoiceNo!=null) {
				Invoice invoice = jdoUtils.getInvoiceByKey(param);
				invoice.setOrderList(jdoUtils.getOrdersByInvoiceNo(invoice.invoiceNo));
				doResponse(resp, invoice, toXml,MODEL_PACKAGE);	// true:JSON
			}else {

			String invoiceNo = req.getParameter("record");
			if (invoiceNo!=null) {
				List<Order> recordList = jdoUtils.getOrdersByInvoiceNo(invoiceNo);

				if (recordList == null || recordList.size() == 0) {
					Status status = new Status();
					status.code = HttpStatus.SC_NO_CONTENT;
					status.message = "No data.";
					try {
						doResponse(resp, status, toXml, MODEL_PACKAGE);
					} catch (Exception ee) {
						ee.printStackTrace();
					}
				} else {
					Invoice invoice = new Invoice();
					invoice.setOrderList(recordList);
					
					doResponse(resp, invoice , toXml, MODEL_PACKAGE);	// true:JSON
				}
			}else {
				
				
				// 各項目で検索

				(new RequestMapper()).setValue(req, param);
				InvoiceBase invoiceBase = new InvoiceBase();
				String pagesize = req.getParameter("pagesize");
				String nextid = req.getParameter("nextid");
				invoiceBase.invoiceList = jdoUtils.getEntriesByParam(param, pagesize, nextid);

				if (invoiceBase.invoiceList == null || invoiceBase.invoiceList.size() == 0) {
					Status status = new Status();
					status.code = HttpStatus.SC_NO_CONTENT;
					status.message = "No data.";
					try {
						doResponse(resp, status, toXml, MODEL_PACKAGE);
					} catch (Exception ee) {
						ee.printStackTrace();
					}
				} else {
					jdoUtils.complementInvoiceRecord(invoiceBase.invoiceList);
					doResponse(resp, invoiceBase , toXml, MODEL_PACKAGE);	// true:JSON
				}
			}
			}
			}
			
	}catch (Exception e) {
		e.printStackTrace();
		Status status = new Status();
		status.code = HttpStatus.SC_INTERNAL_SERVER_ERROR;
		status.message = e.getMessage();
		try {
			doErrorPage(resp, e);
		} catch (Exception ee) {
			ee.printStackTrace();
		}
	}
	}
	
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {

		boolean toXml = true;
		if (req.getParameter("xml")!=null) {
			toXml = false;	// toJSON
		}

		try {

			JdoUtils jdoUtils = new JdoUtils();
			Invoice invoice = (Invoice) getEntity(req, MODEL_PACKAGE);

			try {
				jdoUtils.getInvoiceByKey(invoice);

				// すでに登録されている場合エラー
				Status status = new Status();
				status.code = HttpStatus.SC_CONFLICT;
				status.message = "PK already exists.";
				doResponse(resp, status, toXml, MODEL_PACKAGE);
				
			}catch (JDOObjectNotFoundException e) {

				// 登録されていなければinsert
//				invoice = Instance.blancInvoice(invoice);
				jdoUtils.insert(invoice);
				doResponse(resp, invoice, toXml, MODEL_PACKAGE, HttpStatus.SC_CREATED);

			}
			
		} catch (Exception e) {
			e.printStackTrace();
			Status status = new Status();
			status.code = HttpStatus.SC_INTERNAL_SERVER_ERROR;
			status.message = e.getMessage();
			try {
				doErrorPage(resp, e);
			} catch (Exception ee) {
				ee.printStackTrace();
			}
		}

	}

	public void doPut(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {

		logger.info("put begin.");

		boolean toXml = true;
		if (req.getParameter("xml")!=null) {
			toXml = false;	// toJSON
		}

		try {
			Invoice invoice = (Invoice) getEntity(req, MODEL_PACKAGE);

			logger.info("update step1.");
			// update
			JdoUtils jdoUtils = new JdoUtils();
			jdoUtils.update(invoice);

			logger.info("update step2.");
			Status status = new Status();
			status.code = HttpStatus.SC_OK;
			status.message = "Updated.";
			doResponse(resp, status, toXml, MODEL_PACKAGE);

		} 
		// 楽観的ロック失敗
		catch (ConcurrentModificationException e) {
			logger.info("update step3.");
			Status status = new Status();
			status.code = HttpStatus.SC_CONFLICT;
			status.message = "Optimistic locking failed.";
			try {
				doResponse(resp, status, toXml, MODEL_PACKAGE);
			} catch (Exception ee) {
				ee.printStackTrace();
			}
			
		}
		// 更新エラー
		catch (JDOException e) {
			logger.info("update step4.");
			Status status = new Status();
			status.code = HttpStatus.SC_CONFLICT;
			status.message = "Updating failed.";
			try {
				doResponse(resp, status, toXml, MODEL_PACKAGE);
			} catch (Exception ee) {
				ee.printStackTrace();
			}
			
		}
		catch (Exception e) {
			logger.info("update step5.");
			e.printStackTrace();
			Status status = new Status();
			status.code = HttpStatus.SC_INTERNAL_SERVER_ERROR;
			status.message = e.getMessage();
			try {
				doResponse(resp, status, toXml, MODEL_PACKAGE);
			} catch (Exception ee) {
				ee.printStackTrace();
			}
		}

	}

	public void doDelete(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {

		boolean toXml = true;
		if (req.getParameter("xml")!=null) {
			toXml = false;	// toJSON
		}

		try {

			// delete completely
			String completely = req.getParameter("completely");
			if (completely != null) {
				JdoUtils jdoUtils = new JdoUtils();

				String[] idx = null;
				if (completely.indexOf("-") > 0) {
					idx = completely.split("-");
				} else {
					idx = new String[2];
					idx[0] = "1";
					idx[1] = completely;
				}

				for (long i = Long.parseLong(idx[0]); i <= Long.parseLong(idx[1]); i++) {
					Invoice rec = new Invoice();
					rec.id =i;
					jdoUtils.deleteCompletely(rec);
				}

				Status status = new Status();
				status.code = HttpStatus.SC_OK;
				status.message = completely + " cases were deleted.";
				doResponse(resp, status, toXml, MODEL_PACKAGE);

				return;
			}

			// パラメータからの値を取得
			Invoice param = new Invoice();
			(new RequestMapper()).setValue(req, param);

			// delete
			JdoUtils jdoUtils = new JdoUtils();

			// 削除対象が存在しない場合
			if (jdoUtils.getInvoiceByKey(param)==null) {
				Status status = new Status();
				status.code = HttpStatus.SC_NO_CONTENT;
				status.message = "No content.";
				doResponse(resp, status, toXml, MODEL_PACKAGE);
			}else {
				jdoUtils.delete(param);
				Status status = new Status();
				status.code = HttpStatus.SC_OK;
				status.message = "Deleted.";
				doResponse(resp, status, toXml, MODEL_PACKAGE);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			Status status = new Status();
			status.code = HttpStatus.SC_INTERNAL_SERVER_ERROR;
			status.message = e.getMessage() + "\n";
			try {
				doResponse(resp, status, toXml, MODEL_PACKAGE);
			} catch (Exception ee) {
				ee.printStackTrace();
			}
		}
	}
}
